#include "GY_GraphicsLinearTick.h"
#include<complex>
#include<QtMath>
#include <QPen>
#include <string.h>
#include <QDebug>

GY_GraphicsLinearTick::GY_GraphicsLinearTick(const QString &guid, QGraphicsItem *parent)
    :GY_BasicsGraphicsObject(guid,this,parent)
{
    //图形类型
    GY_Object::setUserData(GY_ENUM::ClassType,QVariant("LinearTick"));
    initializationPropertyInfo();
    updataPen();
    updataBrush();
    UpdateDraw();
    QMap<QVariant,QPointF> editPoints = {
        {"StartPoint",m_PropertyInfoMap["StartPoint"].propertyValue.toPointF()},
        {"EndPoint",m_PropertyInfoMap["EndPoint"].propertyValue.toPointF()},
        {"TickWidthPoint",m_PropertyInfoMap["TickWidthPoint"].propertyValue.toPointF()}
    };
    this->setPen(QColor(Qt::green));
    this->setEditPointF(editPoints);
//    this->setCenterPointF(m_PropertyInfoMap["position"].propertyValue.toPointF());
}

GY_GraphicsLinearTick::GY_GraphicsLinearTick(const QString &guid,
                                             const QPointF &startPoint,const QPointF &endPoint,
                                             const int tickNum,
                                             const qreal tickLenth,
                                             QGraphicsItem *parent)
    :GY_BasicsGraphicsObject(guid,this,parent)
{
    //图形类型
    GY_Object::setUserData(GY_ENUM::ClassType,QVariant("LinearTick"));
    initializationPropertyInfo();
    updataPen();
    updataBrush();
    //初始化图形参数
    m_PropertyInfoMap["StartPoint"].propertyValue=startPoint;
    m_PropertyInfoMap["EndPoint"].propertyValue=endPoint;
    m_PropertyInfoMap["tickNum"].propertyValue=tickNum;
    m_PropertyInfoMap["TickLength"].propertyValue=tickLenth;    
    UpdateDraw();
    QMap<QVariant,QPointF> editPoints = {
        {"StartPoint",m_PropertyInfoMap["StartPoint"].propertyValue.toPointF()},
        {"EndPoint",m_PropertyInfoMap["EndPoint"].propertyValue.toPointF()},
        {"TickWidthPoint",m_PropertyInfoMap["TickWidthPoint"].propertyValue.toPointF()}
    };
    //设置编辑点为红色
    this->setPen(QColor(0,255,0));
    this->setEditPointF(editPoints);
    calculateTickWidthPointPosition();
}
/**
 * @brief initializationPropertyInfo 初始化属性信息
 */
void GY_GraphicsLinearTick::initializationPropertyInfo()
{
    //开始点
    GY_PropertyInfo startPropertyInfo(this);
    startPropertyInfo.propertyName="StartPoint";
    startPropertyInfo.propertyValue=QPointF(0,0);
    startPropertyInfo.updateType = MoveUpdate|Update|PointOfRelative;
    startPropertyInfo.propertyType = PointPropertyType;
    startPropertyInfo.updatePropertyFun=(GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsLinearTick::updateStartPoint;
    m_PropertyInfoMap.insert(startPropertyInfo.propertyName,startPropertyInfo);
    m_PropertyInfoMap[startPropertyInfo.propertyName].setConnect();
    //结束点
    GY_PropertyInfo point2PropertyInfo(this);
    point2PropertyInfo.propertyName="EndPoint";
    point2PropertyInfo.propertyValue=QPointF(50,50);
    point2PropertyInfo.updateType = MoveUpdate|Update|PointOfRelative;
    point2PropertyInfo.propertyType = PointPropertyType;
    point2PropertyInfo.updatePropertyFun=(GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsLinearTick::updateEndPoint;
    m_PropertyInfoMap.insert("EndPoint",point2PropertyInfo);
    m_PropertyInfoMap[point2PropertyInfo.propertyName].setConnect();

    //刻度长度
    GY_PropertyInfo tickLenthPropertyInfo(this);
    tickLenthPropertyInfo.propertyName="TickLength";
    tickLenthPropertyInfo.propertyValue=28;
    tickLenthPropertyInfo.updateType = Update|OrdinaryAttributes;
    tickLenthPropertyInfo.propertyType = QrealPropertyType;
    tickLenthPropertyInfo.updatePropertyFun=(GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsLinearTick::updateTickLenth;
    m_PropertyInfoMap.insert(tickLenthPropertyInfo.propertyName,tickLenthPropertyInfo);
    m_PropertyInfoMap[tickLenthPropertyInfo.propertyName].setConnect();
    //刻度宽度
    GY_PropertyInfo tickWidthPropertyInfo(this);
    tickWidthPropertyInfo.propertyName="TickWidthPoint";
    tickWidthPropertyInfo.propertyValue=QPointF(10,-10);
    tickWidthPropertyInfo.updateType = Update|PointOfRelative;
    tickWidthPropertyInfo.propertyType = PointPropertyType;
    tickWidthPropertyInfo.updatePropertyFun=(GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsLinearTick::updateTickWidth;
    m_PropertyInfoMap.insert(tickWidthPropertyInfo.propertyName,tickWidthPropertyInfo);
    m_PropertyInfoMap[tickWidthPropertyInfo.propertyName].setConnect();
    //刻度数量
    GY_PropertyInfo scaleNumPropertyInfo(this);
    scaleNumPropertyInfo.propertyName="NumTicks";
    scaleNumPropertyInfo.propertyValue=10;
    scaleNumPropertyInfo.updateType = Update|OrdinaryAttributes;
    scaleNumPropertyInfo.propertyType = IntPropertyType;
    scaleNumPropertyInfo.updatePropertyFun=(GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsLinearTick::updateNumTicks;
    m_PropertyInfoMap.insert(scaleNumPropertyInfo.propertyName,scaleNumPropertyInfo);
    m_PropertyInfoMap[scaleNumPropertyInfo.propertyName].setConnect();
    /********************************************公共属性***********************************************/
    GY_PropertyInfo penOpacity(this);
    penOpacity.propertyName = "PenOpacity";
    penOpacity.propertyValue = qreal(1);
    penOpacity.updateType = Update|OrdinaryAttributes;
    penOpacity.propertyType = QrealPropertyType;
    penOpacity.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsLinearTick::updatePenOpacity;
    m_PropertyInfoMap.insert(penOpacity.propertyName,penOpacity);
    m_PropertyInfoMap[penOpacity.propertyName].setConnect();
    //线条样式
    LineStyle ls;
    ls.width = 2;
    ls.cap = "Bott";
    ls.join = "Miter";
    ls.line = "FFFF";
    GY_PropertyInfo lineStyle(this);
    lineStyle.propertyName = "LineStyle";
    lineStyle.propertyValue = QVariant::fromValue(ls);
    lineStyle.updateType = Update|OrdinaryAttributes;
    lineStyle.propertyType = LineStylePropertyType;
    lineStyle.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsLinearTick::updateLineStyle;
    m_PropertyInfoMap.insert("LineStyle",lineStyle);
    m_PropertyInfoMap[lineStyle.propertyName].setConnect();
    //笔颜色
    GY_PropertyInfo penColor(this);
    penColor.propertyName = "PenColor";
    penColor.propertyValue = QColor(255,255,255);
    penColor.updateType = Update|OrdinaryAttributes;
    penColor.propertyType = ColorPropertyType;
    penColor.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsLinearTick::updatePenColor;
    m_PropertyInfoMap.insert("PenColor",penColor);
    m_PropertyInfoMap[penColor.propertyName].setConnect();

    GY_PropertyInfo penAttributes(this);
    penAttributes.propertyName = "PenAttributes";
    penAttributes.propertyValue = false;
    penAttributes.updateType = Update|OrdinaryAttributes;
    penAttributes.propertyType = BoolPropertyType;
    penAttributes.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsLinearTick::updatePenAttributes;
    m_PropertyInfoMap.insert("PenAttributes",penAttributes);
    m_PropertyInfoMap[penAttributes.propertyName].setConnect();

    GY_PropertyInfo isVisible(this);
    isVisible.propertyName = "IsVisible";
    isVisible.propertyValue = true;
    isVisible.updateType = Update|OrdinaryAttributes;
    isVisible.propertyType = BoolPropertyType;
    isVisible.updatePropertyFun = (GY_PropertyInfo::UpdatePropertyFun)&GY_GraphicsLinearTick::updateIsVisible;
    m_PropertyInfoMap.insert(isVisible.propertyName,isVisible);
    m_PropertyInfoMap[isVisible.propertyName].setConnect();
}
/**
 * @brief UpdateDraw 更新绘制
 */
void GY_GraphicsLinearTick::UpdateDraw()
{
        QPointF startPoint=m_PropertyInfoMap.value("StartPoint").propertyValue.toPointF();
        QPointF endPoint=m_PropertyInfoMap.value("EndPoint").propertyValue.toPointF();
        //结束点相对开始点的坐标
        QPointF diffPoint=endPoint-startPoint;
        qreal tickLength=m_PropertyInfoMap.value("TickLength").propertyValue.toDouble();
//        qreal tickWidth=m_PropertyInfoMap.value("TickWidth").propertyValue.toDouble();
        int tickNum=m_PropertyInfoMap.value("NumTicks").propertyValue.toInt();
        //结束点相对开始点的角度
        qreal angle=qRadiansToDegrees(qAtan2(diffPoint.y(),diffPoint.x()));
        //刻度线中心点间距
        qreal diffX=diffPoint.x()/(tickNum-1);
        qreal diffY=diffPoint.y()/(tickNum-1);
        QPainterPath path;
        for (int i = 0; i < tickNum; ++i)
        {
            QPointF tickCentrePoint(startPoint.x()+diffX*i,startPoint.y()+diffY*i);//中心拖拽圆点位置
            QPointF tickStartPoint=precalculatedPosition(tickLength/2,angle+90)+tickCentrePoint;
            QPointF tickEndPoint=precalculatedPosition(tickLength/2,angle-90)+tickCentrePoint;
            path.moveTo(tickStartPoint);
            path.lineTo(tickEndPoint);
        }
        path.closeSubpath();
        this->setPath(path);
}
/**
 * @brief updateStartPoint  更新开始点
 * @param name 属性名称
 * @param value 中心点位置
 * @return 是否更新成功
 */
bool GY_GraphicsLinearTick::updateStartPoint(const QString &name, const QVariant &value)
{
    if(!value.canConvert<QPointF>())
    {
        return false;
    }
    QPointF point;
    point = this->mapFromScene(value.toPointF());
    m_PropertyInfoMap[name].propertyValue=point;
    calculateTickWidthPointPosition();
    UpdateDraw();
    this->setEditPointF(name,m_PropertyInfoMap[name].propertyValue.toPointF());
    return true;
}
/**
 * @brief updateEndPoint  更新结束点
 * @param name 属性名称
 * @param value 中心点位置
 * @return 是否更新成功
 */
bool GY_GraphicsLinearTick::updateEndPoint(const QString &name, const QVariant &value)
{
    if(!value.canConvert<QPointF>())
    {
        return false;
    }
    QPointF point;
    point = this->mapFromScene(value.toPointF());
    m_PropertyInfoMap[name].propertyValue=point;
    calculateTickWidthPointPosition();
    UpdateDraw();
    this->setEditPointF(name,m_PropertyInfoMap[name].propertyValue.toPointF());
    return true;
}
/**YYZ
 * @brief updateTickWidthPoint  更新宽度设置点
 * @param name 属性名称
 * @param value 中心点位置
 * @return 是否更新成功
 */
bool GY_GraphicsLinearTick::updateTickWidthPoint(const QString &, const QVariant &value)
{
    if(!value.canConvert<QPointF>())
    {
        return false;
    }
    //鼠标位置
    QPointF point=this->mapFromScene(value.toPointF());//屏幕坐标转本地坐标
    QPointF startPoint=m_PropertyInfoMap.value("StartPoint").propertyValue.toPointF();
    QPointF endPoint=m_PropertyInfoMap.value("EndPoint").propertyValue.toPointF();
    //结束点相对开始点的坐标
    QPointF diffPoint=endPoint-startPoint;
    point=point-startPoint;
//    qreal tickLength=m_PropertyInfoMap.value("TickLength").propertyValue.toDouble();
    //结束点相对开始点的角度
    qreal angle=qRadiansToDegrees(qAtan2(diffPoint.y(),diffPoint.x()));
    qreal mouseAngle=qRadiansToDegrees(qAtan2(point.y(),point.x()));//弧度转角度
    qreal mouseLength=qSqrt(qPow(point.x(),2)+qPow(point.y(),2));
    qreal projectedLength=qAbs(mouseLength) * qCos(qDegreesToRadians(angle+90-mouseAngle));
    m_PropertyInfoMap["TickLength"].propertyValue=projectedLength*2;
    calculateTickWidthPointPosition();
    UpdateDraw();
    return true;
}
/**
 * @brief calculateTickWidthPointPosition 计算宽度编辑点位置
 */
void GY_GraphicsLinearTick::calculateTickWidthPointPosition()
{
    qreal length=m_PropertyInfoMap["TickLength"].propertyValue.toDouble();//线条长度（两倍投影长度）
    QPointF startPoint=m_PropertyInfoMap.value("StartPoint").propertyValue.toPointF();
    QPointF endPoint=m_PropertyInfoMap.value("EndPoint").propertyValue.toPointF();
    //结束点相对开始点的坐标
    QPointF diffPoint=endPoint-startPoint;
    qreal angle=qRadiansToDegrees(qAtan2(diffPoint.y(),diffPoint.x()));
    QPointF tickWidthPoint=precalculatedPosition(length/2,angle+90)+startPoint;
//    qDebug()<<"diffPoint="<<diffPoint<<"angle="<<angle<<"tickWidthPoint="<<tickWidthPoint;
    m_PropertyInfoMap["TickWidthPoint"].propertyValue=tickWidthPoint;
    this->setEditPointF("TickWidthPoint",tickWidthPoint);
}
/**
 * @brief updateTickLenth 更新刻度线长度
 * @param name 属性名称
 * @param value 刻度数量
 * @return 是否更新成功
 */
bool GY_GraphicsLinearTick::updateTickLenth(const QString &name, const QVariant &value)
{
    if(!value.canConvert<double>())
    {
        return false;
    }
    m_PropertyInfoMap[name].propertyValue=value;
    QPointF startPoint=m_PropertyInfoMap.value("StartPoint").propertyValue.toPointF();
    QPointF endPoint=m_PropertyInfoMap.value("EndPoint").propertyValue.toPointF();
    QPointF diffPoint=endPoint-startPoint;
    qreal angle=qRadiansToDegrees(qAtan2(diffPoint.y(),diffPoint.x()));
    QPointF tickWidthPoint=precalculatedPosition(value.toDouble()/2,angle+90)+startPoint;
    m_PropertyInfoMap["TickWidthPoint"].propertyValue=tickWidthPoint;
    this->setEditPointF("TickWidthPoint",tickWidthPoint);
    UpdateDraw();
    return true;
}
/**
 * @brief updateNumTicks 更新刻度数量
 * @param name 属性名称
 * @param value 刻度数量
 * @return 是否更新成功
 */
bool GY_GraphicsLinearTick::updateNumTicks(const QString &name, const QVariant &value)
{
//    qDebug() << "***" << value.type();
    if(!value.canConvert<int>()||value.toInt()<=0)
    {
        return false;
    }
    m_PropertyInfoMap[name].propertyValue=value;
    UpdateDraw();
    return true;
}
/**YYZ功能函数
 * @brief updateTickWidth 更新刻度线宽度
 * @param name 属性名称
 * @param value 鼠标当前坐标
 * @return 是否更新成功
 */
bool GY_GraphicsLinearTick::updateTickWidth(const QString &name, const QVariant &value)
{
    if(!value.canConvert<QPointF>())
    {
        return false;
    }
    //鼠标位置
    QPointF point;
    point = this->mapFromScene(value.toPointF());
    QPointF startPoint=m_PropertyInfoMap.value("StartPoint").propertyValue.toPointF();
    QPointF endPoint=m_PropertyInfoMap.value("EndPoint").propertyValue.toPointF();
    //结束点相对开始点的坐标
    QPointF diffPoint=endPoint-startPoint;
    point=point-startPoint;
    qreal angle=qRadiansToDegrees(qAtan2(diffPoint.y(),diffPoint.x()));

    qreal mouseAngle=qRadiansToDegrees(qAtan2(point.y(),point.x()));//弧度转角度
    qreal mouseLength=qSqrt(qPow(point.x(),2)+qPow(point.y(),2));
    qreal projectedLength=qAbs(mouseLength) * qCos(qDegreesToRadians(angle+90-mouseAngle));
    m_PropertyInfoMap["TickLength"].propertyValue=projectedLength*2;
//    qDebug()<<"angle="<<angle<<"mouseAngle="<<mouseAngle<<"mouseLength="<<mouseLength<<"projectedLength="<<projectedLength;
    UpdateDraw();
    QPointF tickWidthPoint=precalculatedPosition(projectedLength,angle+90)+startPoint;
    m_PropertyInfoMap["TickWidthPoint"].propertyValue=tickWidthPoint;
    this->setEditPointF(name,tickWidthPoint);
    return true;
}
/**
 * @brief precalculatedPosition 计算点位置
 * @param radius 半径
 * @param angele 角度
 * @return 计算得到的点位置
 */
QPointF GY_GraphicsLinearTick::precalculatedPosition(const double radius,const double angele)
{
    qreal radian=qDegreesToRadians(angele); //角度转弧度
    QPointF resultPoint;
    resultPoint.setX(cos(radian)*radius);
    resultPoint.setY(sin(radian)*radius);
    return resultPoint;//返回极坐标并转为平面直角坐标
}


